package com.atguigu.tingshu.album.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.album.util.FileUtil;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserPaidTrack;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserClientFeign;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse;
import com.tencentcloudapi.vod.v20180717.models.MediaBasicInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaMetaData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    VodConstantProperties vodConstantProperties;
    @Autowired
    TrackStatMapper trackStatMapper;
    @Autowired
    OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    VodService vodService;
    @Autowired
    AlbumInfoMapper albumInfoMapper;
    @Autowired
    FileUtil fileUtil;
    @Autowired
    UserClientFeign userClientFeign;

    /**
     * @param trackInfoQuery
     * @param trackListVoPage
     * @return
     */
    @Override
    public Object findUserTrackPage(TrackInfoQuery trackInfoQuery,
                                    Page<TrackListVo> trackListVoPage) {
        return trackInfoMapper.selectTrackInfo(trackInfoQuery, trackListVoPage);
    }

    /**
     * 上传声音接口实现
     *
     * @param file
     * @return
     */
    @Override
    @SneakyThrows
    public Object uploadTrack(MultipartFile file) {
        // 用自定义工具类将用户上传的文件存储到本地
        String uploadTempPath = UploadFileUtil
                .uploadTempPath(vodConstantProperties.getTempPath(), file);

        // 初始化腾讯云客户端
        VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId()
                , vodConstantProperties.getSecretKey());

        // 构建上传请求对象
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(uploadTempPath);

        // 调用上传
        VodUploadResponse response = client.upload(vodConstantProperties.getRegion()
                , request);

        // 获取文件唯一识别码
        String vodFileId = response.getFileId();
        // 获取文件播放地址
        String vodMediaUrl = response.getMediaUrl();

        // 包装返回结果:唯一标识码+播放地址
        JSONObject result = new JSONObject();
        result.put("mediaFileId", vodFileId);
        result.put("mediaUrl", vodMediaUrl);
        // 返回声音的播放的url
        return result;
    }


    /**
     * 新增声音
     *
     * @param trackInfoVo
     */
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        // 声明DO
        TrackInfo trackInfo = new TrackInfo();
        // 属性转移
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 补全用户id
        trackInfo.setUserId(AuthContextHolder.getUserId());
        // 调用腾讯云查询声音的详细信息
        MediaInfo mediaInfo = vodService.getTrackDetailInfo(trackInfo.getMediaFileId());
        // 获取basicInfo
        MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
        // 获取声音类型并补全
        String type = basicInfo.getType();
        trackInfo.setMediaType(type);
        // 获取声音地址并补全
        String mediaUrl = basicInfo.getMediaUrl();
        trackInfo.setMediaUrl(mediaUrl);
        // 获取元数据
        MediaMetaData metaData = mediaInfo.getMetaData();
        // 获取声音时长并补全
        Float duration = metaData.getDuration();
        trackInfo.setMediaDuration(new BigDecimal(duration.toString()));
        // 获取声音大小并补全
        Long size = metaData.getSize();
        trackInfo.setMediaSize(size);
        // 查询专辑的最大order_num，不存在初始化，存在+1
        Integer orderNumber = trackInfoMapper.selectTrackMaxOrderNum(trackInfo.getAlbumId());
        if (orderNumber == null) {
            orderNumber = 0;
        }
        trackInfo.setOrderNum(orderNumber + 1);
        // 保存DO到DB
        save(trackInfo);
        // 获取声音id
        Long trackInfoId = trackInfo.getId();
        // 初始化声音的统计信息
        initTrackStat(trackInfoId);
        // 查询专辑数据
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        if (albumInfo == null) {
            // 若专辑不存在 则抛出异常
            throw new GuiguException(201, "声音保存失败");
        }
        // 专辑的声音数量+1
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);
        // albumInfoMapper.update(albumInfo, null);
    }


    /**
     * 删除声音
     *
     * @param trackId
     */
    @Override
    public void removeTrackInfo(Long trackId) {
        // 校验条件-查询声音是否存在
        TrackInfo delTrackInfo = getOne(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getUserId, AuthContextHolder.getUserId())
                        .eq(TrackInfo::getId, trackId));
        // 若不存在抛异常
        if (delTrackInfo == null) {
            throw new GuiguException(201, "声音不存在");
        }
        // 删除声音封面
        String coverUrl = delTrackInfo.getCoverUrl();
        fileUtil.deleteFile(coverUrl);
        // 校验是否删除成功
        if (!removeById(trackId)) {
            throw new GuiguException(201, "删除声音失败");
        }
        // 删除声音统计表
        trackStatMapper.delete(
                new LambdaQueryWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, trackId));
        // 专辑声音-1后更新专辑数据
        AlbumInfo albumInfo = albumInfoMapper.selectById(delTrackInfo.getAlbumId());
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
        // 删除云点播文件
        vodService.removeFile(delTrackInfo.getMediaFileId());
    }

    /**
     * 修改声音
     *
     * @param trackId
     * @param trackInfoVo
     */
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        // 查询校验声音是否存在
        TrackInfo trackInfo = getOne(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getUserId, AuthContextHolder.getUserId())
                        .eq(TrackInfo::getId, trackId));
        if (trackInfo == null) {
            throw new GuiguException(201, "声音不存在");
        }
        // 提取新旧声音文件id
        String oldMediaFileId = trackInfo.getMediaFileId();
        String newMediaFileId = trackInfoVo.getMediaFileId();
        // 复制更新属性后判断声音文件是否有变化
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 若有变化，则删除旧声音，保存新声音
        if (!oldMediaFileId.equals(newMediaFileId)) {
            vodService.removeFile(oldMediaFileId);
            // 获取新声音数据更新到声音表
            MediaInfo mediaInfo = vodService.getTrackDetailInfo(newMediaFileId);
            MediaMetaData metaData = mediaInfo.getMetaData();
            MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
            // 文件大小
            trackInfo.setMediaSize(metaData.getSize());
            // 时长
            trackInfo.setMediaDuration(new BigDecimal(metaData.getDuration().toString()));
            // url
            trackInfo.setMediaUrl(basicInfo.getMediaUrl());
            // 类型
            trackInfo.setMediaType(basicInfo.getType());
        }
        // DB修改声音的数据
        updateById(trackInfo);
    }


    /**
     * 专辑详情页面声音列表
     *
     * @param albumId
     * @param page
     * @param size
     * @return
     */
    @Override
    public Object findAlbumTrackPage(Long albumId, Integer page, Integer size) {
        // 初始化返回结果
        Object result = null;
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在，声音不存在");
        }
        // 获取专辑类型
        String payType = albumInfo.getPayType();
        // 分支 -- 返回结果赋值
        switch (payType) {
            // 免费专辑
            case "0101" -> result = freeAlbum(albumId, page, size);

            // vip免费专辑
            case "0102" -> result = vipAlbum(albumInfo, page, size);

            // 付费专辑
            case "0103" -> result = payAlbum(albumInfo, page, size);

        }
        return result;
    }


    /**
     * 声音详情页面
     * 查询声音的统计信息
     *
     * @param trackId
     * @return
     */
    @Override
    public Object getTrackStatVo(Long trackId) {
        // 查询指定声音的全部统计信息
        List<TrackStat> trackStats = trackStatMapper.selectList(
                new LambdaQueryWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, trackId));
        // 转为map
        Map<String, Integer> trackStatMap = trackStats.stream().collect(Collectors.toMap(
                key -> key.getStatType(),
                value -> value.getStatNum()
        ));
        // 初始化并包装返回结果
        TrackStatVo trackStatVo = new TrackStatVo();
        trackStatVo.setPlayStatNum(trackStatMap.get("0701"));
        trackStatVo.setCollectStatNum(trackStatMap.get("0702"));
        trackStatVo.setPraiseStatNum(trackStatMap.get("0703"));
        trackStatVo.setCommentStatNum(trackStatMap.get("0704"));
        // 返回
        return trackStatVo;
    }


    /**
     * 查询用户可购买的当前专辑的指定声音和后面所有可购买的声音list
     * @param trackId
     * @return
     */
    @Override
    public Object findUserTrackPaidLis(Long trackId) {
        // 查询当前id的声音详情
        TrackInfo trackInfo = getById(trackId);
        // 获取声音所在专辑详情
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        // 获取该专辑中当前声音后的声音list
        List<TrackInfo> trackInfoList = list(new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, albumId)
                        .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum()));
        // 查询用户购买过的声音map
        Map<String, Object> userPaidTrackMap =
                userClientFeign.getUserPaidTrack(albumId, AuthContextHolder.getUserId());
        // 查询用户已下单但未支付的声音map
        Map<String, Object> userTrackOrderMap =
                orderInfoFeignClient.getUserTrackOrderInfo(AuthContextHolder.getUserId());
        // 过滤 1.已购 2.已下单未付款 声音，筛选可购声音list
        List<TrackInfo> trackInfoListAvailable = trackInfoList.stream()
                .filter(trackInfoObj ->
                        userPaidTrackMap.get(trackInfoObj.getId().toString()) == null &&
                        userTrackOrderMap.get(trackInfoObj.getId().toString()) == null)
                .limit(50)
                .collect(Collectors.toList());
        // 获取单价
        BigDecimal price = albumInfo.getPrice();
        // 初始化结果list
        List<JSONObject> result = new ArrayList<>();
        // 包装 本集 数据
        JSONObject trackAvailable = new JSONObject();
        trackAvailable.put("name", "第" + trackInfo.getOrderNum() + "集");
        trackAvailable.put("trackCount", "1");
        trackAvailable.put("price", price);
        result.add(trackAvailable);
        // 包装 剩下集数
        int size = trackInfoListAvailable.size();
        // 若可购集数 > 1
        if (size > 1){
            // 计算可购买套餐
            int count = size % 10 == 0 ? (size / 10) : (size / 10) + 1 ;
            // 包装购买套餐标签
            for (int i = 1; i <= count ; i++) {
                // 初始化
                trackAvailable = new JSONObject();
                // 当前套餐包含集数
                int episode = i * 10;
                if (episode > size){
                    trackAvailable.put("name", "后" + size + "集");
                    trackAvailable.put("trackCount", size + "");
                    trackAvailable.put("price", price.multiply(new BigDecimal(size)));
                }else {
                    trackAvailable.put("name", "后" + i*10 + "集");
                    trackAvailable.put("trackCount",  i*10 + "");
                    trackAvailable.put("price", price.multiply(new BigDecimal(i*10)));
                }
                result.add(trackAvailable);
            }
        }
        // 返回结果
        return result;
    }

    /**
     * 付费专辑
     *
     * @param albumInfo
     * @param page
     * @param size
     * @return
     */
    private Page<AlbumTrackListVo> payAlbum(AlbumInfo albumInfo,
                                            Integer page,
                                            Integer size) {
        // 查询免费数量
        Integer tracksForFree = albumInfo.getTracksForFree();
        // 查询声音
        Page<AlbumTrackListVo> result =
                trackInfoMapper.selectPageTrackInfoListByAlbumId(albumInfo.getId(),
                        new Page<AlbumTrackListVo>(page, size));
        Long userId = AuthContextHolder.getUserId();
        // 获取付费类型 0201-单集 0202-专辑
        String priceType = albumInfo.getPriceType();
        if (priceType.equals("0201")) { //
            Map<String, Object> userPaidTrackMap =
                    userClientFeign.getUserPaidTrack(albumInfo.getId(), userId);
            // 对比是否购买过
            List<AlbumTrackListVo> recordsNew = result.getRecords().stream().map(albumTrackListVo -> {
                if (userPaidTrackMap.get(albumTrackListVo.getTrackId().toString()) == null &&
                        albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            result.setRecords(recordsNew);
            return result;
        } else {
            // 整张专辑购买
            if (userClientFeign.getUserPaidAlbum(albumInfo.getId(), userId)) {
                // 买了 直接返回
                return result;
            } else {
                // 没买 --- 试听以外全收费
                List<AlbumTrackListVo> recordsNew = result.getRecords().stream().map(albumTrackListVo -> {
                    if (albumTrackListVo.getOrderNum() > tracksForFree) {
                        albumTrackListVo.setIsShowPaidMark(true);
                    }
                    return albumTrackListVo;
                }).collect(Collectors.toList());
                result.setRecords(recordsNew);
                return result;
            }
        }
    }


    /**
     * VIP用户免费专辑
     *
     * @param albumInfo
     * @param page
     * @param size
     * @return
     */
    private Page<AlbumTrackListVo> vipAlbum(AlbumInfo albumInfo, Integer page, Integer size) {
        // 查询声音数据
        Page<AlbumTrackListVo> result =
                trackInfoMapper.selectPageTrackInfoListByAlbumId(albumInfo.getId(),
                        new Page<AlbumTrackListVo>(page, size));
        // 获取专辑免费试听集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        // 获取当前线程用户
        Integer vip = AuthContextHolder.getVip();
        if (vip.equals(0)) {
            // 普通用户 - 免费试听 + 去购买
            List<AlbumTrackListVo> recordsNew = result.getRecords().stream().map(albumTrackListVo -> {
                // 大于试听集数的收费
                if (albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            result.setRecords(recordsNew);
            return result;
        } else {
            // VIP用户 - 免费
            return result;
        }
    }


    /**
     * 免费专辑
     *
     * @param albumId
     * @param page
     * @param size
     * @return
     */
    private Page<AlbumTrackListVo> freeAlbum(Long albumId, Integer page, Integer size) {
        // 查询该专辑下的声音数据
        return trackInfoMapper.selectPageTrackInfoListByAlbumId(albumId,
                new Page<AlbumTrackListVo>(page, size));
    }


    /**
     * 新增声音 - 初始化声音统计
     *
     * @param trackInfoId
     */
    private void initTrackStat(Long trackInfoId) {
        // 初始化DO
        TrackStat trackStat = new TrackStat();
        // 补齐字段值
        trackStat.setTrackId(trackInfoId);
        // 初速数据值
        trackStat.setStatNum(0);
        // 初始化播放并保存
        trackStat.setStatType(SystemConstant.TRACK_STAT_PLAY);
        trackStatMapper.insert(trackStat);
        // 收藏
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.TRACK_STAT_COLLECT);
        trackStatMapper.insert(trackStat);
        // 点赞
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.TRACK_STAT_PRAISE);
        trackStatMapper.insert(trackStat);
        // 评论
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.TRACK_STAT_COMMENT);
        trackStatMapper.insert(trackStat);
    }

    /**
     * 查询即将确认订单的声音
     * @param trackId
     * @return
     */
    @Override
    public JSONObject getTrackListAndPrice(Long trackId) {
        // 查询声音详情
        TrackInfo trackInfo = getById(trackId);
        // 获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        // 获取当前声音后的所有声音
        List<TrackInfo> trackInfoList = list(new LambdaQueryWrapper<TrackInfo>()
                .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .eq(TrackInfo::getAlbumId, albumInfo.getId()));
        // 返回结果初始化
        JSONObject result = new JSONObject();
        // 赋值
        result.put("trackInfoList",trackInfoList);
        result.put("price",albumInfo.getPrice());
        result.put("albumId",albumInfo.getId());
        // 返回
        return result;
    }
}
